package org.hashdb.client.cmd;

import jline.console.UserInterruptException;
import org.hashdb.client.manager.AppContext;
import org.hashdb.client.manager.ConfigurableAppContext;
import org.hashdb.client.manager.NioAppContext;
import org.hashdb.client.util.event.AbstractEventEngin;

import java.io.IOException;
import java.util.LinkedList;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * Date: 2024/1/8 19:16
 *
 * @author huanyuMake-pecdle
 * @version 0.0.1
 */
public class CommandExecutorDispatcher extends AbstractEventEngin<CommandExecutorDispatcher> {
    private final AppContext ctx;

    private String singleLinePrompt;

    private String multiLinePrompt;

    private static final String anonymUser = "anonym";

    private boolean start;

    private boolean started;

    {
        updatePrompt(anonymUser);
    }

    public CommandExecutorDispatcher(AppContext appContext) {
        super((msg) -> appContext.reader().errorLn("not found listener. msg: '" + msg + "'"));
        ctx = appContext;
        if (appContext instanceof ConfigurableAppContext configurableAppContext) {
            configurableAppContext.onAuthPass(this::updatePrompt);
            configurableAppContext.onAuthExpire(() -> updatePrompt(anonymUser));
        } else if (appContext instanceof NioAppContext nioAppContext) {
            nioAppContext.register("setKey", p -> {
                String username = (String) p;
                updatePrompt(username == null ? anonymUser : username);
            });
        }
    }

    public void pausePublishFormReader() {
        started = start;
        start = false;
    }

    public void tryPublishFormReader() {
        if (started) {
            startPublishFormReader();
        }
    }

    @SuppressWarnings("InfiniteLoopStatement")
    public void startPublishFormReader() {
        if (start) {
            return;
        }
        start = true;
        var commandFragments = new LinkedList<String>();
        try {
            while (start) {
                try {
                    var fragment = ctx.reader().readLine(commandFragments.isEmpty() ? singleLinePrompt : multiLinePrompt);
                    if (fragment.endsWith("\\")) {
                        commandFragments.add(fragment.substring(0, fragment.length() - 1));
                        continue;
                    }
                    commandFragments.add(fragment);
                } catch (UserInterruptException e) {
                    commandFragments.clear();
                    continue;
                }
                var singleLineCommand = String.join("", commandFragments);
                commandFragments.clear();
                publish(singleLineCommand, null);
            }
        } catch (UserInterruptException e) {
            publish(UserInterruptException.class, e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void updatePrompt(String username) {
        multiLinePrompt = IntStream.range(0, username.length()).mapToObj(i -> " ").collect(Collectors.joining()) + "   >";
        singleLinePrompt = "[" + username + "] >";
    }
}
